const net = require('net');
const CryptoJS = require('crypto-js');
const http = require('http');
const configuration = require("./configuration.json");
const express = require('express');
const { SHA256 } = require('crypto-js');
const app = express();
process.env.domain = null;
const password = configuration.Password;

    // Defense from crash.
    process.on('unhandledRejection', (error, promise) => {});

    // Initiailization.

    if (configuration.PortForwarding == true)
    {
        const NatAPI = require('nat-api')
        const client = new NatAPI();

        client.map(8050, (err) => {
            if (err) return console.log('Error', err)
            console.log((new Date()), "Port successfuly forwarded.");
        });
    }


    http.get('http://icanhazip.com', (response) => {
        let cache = "";
        response.on("data", (data) => {
            cache += data;
        });

        response.on("end", () => {
            console.log((new Date()), "Password:", password);
            console.log((new Date()), "Mailbox:", CryptoJS.AES.encrypt(cache.trim(), password).toString());
        });
    });

/**
 * Mail
 */
    let acceptedMails = [
        {
            "readed": "✕",
            "date": (new Date()),
            "from": "You",
            "title": "Welcome!",
            "text": "Welcome to still possible, free, and important thing, decentralized P2P Mail messaging. Contact your friends, receive verification codes, fast, and destroy your mailbox in one touch. Your mailbox is not dependent on any company, centralized server, or something like it. You can get more with GNU Project software and open source projects, and even our project couldn't exist without Open Source Project, you can safely remove this message from your mailbox and continue to receive and send messages through the AES Encryption and a lot of nodes for free, as long, as your mailbox is online. Next start - new mailbox.",
        }
    ];


// The Mail Router.

app.get("/", (req, res) => {
    let mails = "";
    if (acceptedMails.length > 0)
    {
        for (let x = 0; x < acceptedMails.length; x++)
        {
            mails += `
            <tr>
                <td>${acceptedMails[x].readed}</td>
                <td>${acceptedMails[x].date}</td>
                <td>${acceptedMails[x].from}</td>
                <td>${acceptedMails[x].title}</td>
                <td><a href='http://127.0.0.1:8040/:mails/read?id=${x}'>Read</a></td>
                <td><a href='http://127.0.0.1:8040/:mails/remove?id=${x}'>🗑</a></td>
            </tr>
            `
        }
    } 
    else
    {
        if (acceptedMails.length == 0)
        {
            mails = "No one mail was received. Try again later (Is not an error)";
        }
    }
    res.send(`
        <h2>The Mail Router ✉</h2>
        <div class='menu'>
            <a href='http://127.0.0.1:8040/:mails/send'>Send</a>
            <a href='http://127.0.0.1:8040/stop'>Stop mail node.</a>
        </div>
        <p>Your mailbox</p>
        <p></p>
        <style>
        table, th, td {
            border: 1px solid black;
            border-collapse: collapse;
          }
          th, td {
            padding: 15px;
          }   
        .menu {
            display: inline-block;
        }
        .menu a {
            padding: 5px;
            text-decoration: none;
        }
        </style>
        <table>
            <tr>
                <th>Readed</th>
                <th>Date</th>
                <th>From</th>
                <th>Title</th>
                <th>Link</th>
            </tr>
            ${mails}</p>
        </table>
    `);
});

app.get("/:mails/read", (req, res) => {
    
    res.send(`
    <h2>The Mail Router ✉</h2>
    <p>Your mail</p>
    <code>
        <p>Readed : ${acceptedMails[req.query.id].readed}</p>
        <p>Date : ${acceptedMails[req.query.id].date}</p>
        <p>From : ${acceptedMails[req.query.id].from}</p>
        <p>Title : ${acceptedMails[req.query.id].title}</p>
        <p>Text : ${acceptedMails[req.query.id].text}</p>
    </code>
    <p><a href='http://127.0.0.1:8040/'>Your mailbox</a></p>
    `);
    acceptedMails[req.query.id].readed = "✓"
})

app.get("/:mails/remove/", (req, res) => {
    acceptedMails.splice(req.query.id, 1);
    res.send(`
    <h2>The Mail Router ✉</h2>
    <p>Mail deleted.</p>
    <p>Your mail has been sent to traveling to the <b>/dev/null</b>.<br>Goodbye, Mr. Mail #${req.query.id}</p>
    <p><a href='http://127.0.0.1:8040/'>Your mailbox</a></p>
    `)
});

app.get("/:mails/send", (req, res) => {
    res.send(`
    <h2>The Mail Router ✉</h2>
    <p>Send mail</p>
    <style>
        form p {
            
        }
    </style>
    <code>
        <form action='http://127.0.0.1:8040/:mails/send_api'>
            <label for='to'>Send to:</label><br>
            <p>&nbsp;<input name='to' placeholder='Remote user email.' required id='to'></p>
            <label for='title'>Title:</label><br>
            <p>&nbsp;<input name='title' placeholder='Title' required id='title'></p>
            <label for='text'>Text:</label><br>
            <p>&nbsp;<textarea name='text' placeholder='Contents' required id='text'></textarea></p>
            <label for='password'>Password:</label><br>
            <p>&nbsp;<input name='password' placeholder='Password' type='password' required id='password'></p>
            <p>&nbsp;<button type='submit'>Send</button></p>
        </form>
        <p><a href='http://127.0.0.1:8040/'>Your mailbox</a></p>
    </code>
    `);
})

app.get("/:mails/send_api", (req, res) => {
    const hostname_b = CryptoJS.AES.decrypt(req.query.to, req.query.password);
    const hostname = hostname_b.toString(CryptoJS.enc.Utf8);
    const mailSender = net.createConnection({
        "host": hostname,
        "port": 8050,
    });

    const package = {
        "From": CryptoJS.AES.encrypt(process.env.domain, req.query.password).toString(),
        "Title": CryptoJS.AES.encrypt(req.query.title, req.query.password).toString(),
        "Text": CryptoJS.AES.encrypt(req.query.text, req.query.password).toString(),
    };
    lastMessageSignature = SHA256(package).toString();
    mailSender.write(Buffer.from(JSON.stringify(package)));

    mailSender.on("data", data => {
        if (data == "OK")
        {
            res.send(`
            <h2>The Mail Router ✉</h2>
            <p>Delivery have been competed.</p>
            <p><a href='http://127.0.0.1:8040/'>Your mailbox</a></p>
            `);
            console.log((new Date()), "Delivery complete.");
        }
        else
        {
            res.send(`
            <h2>The Mail Router ✉</h2>
            <p>Delivery failed. You have to try again.</p>
            <p><a href='http://127.0.0.1:8040/'>Your mailbox</a></p>
            `);
            console.log((new Date()), "Delivery failed.");
        }
    });
})
app.listen(8040, '127.0.0.1');

try
{
    const background = net.createServer(server => {

        server.on("connect", () => {
            console.log((new Date()), "New connection received.");
        });
    
        server.on("data", data => {
            let package = JSON.parse(data.toString('utf8'));
    
            package.From = CryptoJS.AES.decrypt(package.From, password);
            package.Title = CryptoJS.AES.decrypt(package.Title, password);
            package.Text = CryptoJS.AES.decrypt(package.Text, password);
    
            const Text = package.Text.toString(CryptoJS.enc.Utf8);
            const Title = package.Title.toString(CryptoJS.enc.Utf8);
            const From = package.From.toString(CryptoJS.enc.From);
    
            acceptedMails.push(
                {
                    "date": new Date(),
                    "from": From,
                    "readed": "✕",
                    "text": Text,
                    "title": Title,
                }
            );
    
            server.write("OK");
        });
    
    }).listen(8050, '0.0.0.0');
} catch (e) {}